package ch.retorte.intervalmusiccompositor.player; import static ch.retorte.intervalmusiccompositor.commons.Utf8Bundle.getBundle; import java.io.IOException; import javax.sound.sampled.AudioFormat; import javax.sound.sampled.AudioInputStream; import javax.sound.sampled.AudioSystem; import javax.sound.sampled.DataLine; import javax.sound.sampled.LineUnavailableException; import javax.sound.sampled.SourceDataLine; import ch.retorte.intervalmusiccompositor.audiofile.IAudioFile; import ch.retorte.intervalmusiccompositor.commons.MessageFormatBundle; import ch.retorte.intervalmusiccompositor.messagebus.DebugMessage; import ch.retorte.intervalmusiccompositor.messagebus.ErrorMessage; import ch.retorte.intervalmusiccompositor.spi.audio.MusicPlayer; import ch.retorte.intervalmusiccompositor.spi.messagebus.MessageProducer; import ch.retorte.intervalmusiccompositor.util.SoundHelper; /** * @author nw */ public class ExtractMusicPlayer implements Runnable, MusicPlayer { private static final int AUDIO_BUFFER_SIZE = 32768; private MessageFormatBundle bundle = getBundle("core_imc"); private AudioInputStream inputStream; private Boolean play = false; private MessageProducer messageProducer; private SoundHelper soundHelper; public ExtractMusicPlayer(MessageProducer messageProducer) { this.messageProducer = messageProducer; this.soundHelper = new SoundHelper(messageProducer); } @Override public void run() { play = true; playPCM(inputStream); } public void stop() { play = false; } private Boolean isPlaying() { return play; } private void playPCM(AudioInputStream inputStream) { try { AudioFormat audioFormat = inputStream.getFormat(); DataLine.Info info = new DataLine.Info(SourceDataLine.class, audioFormat); SourceDataLine line = (SourceDataLine) AudioSystem.getLine(info); line.open(audioFormat); line.start(); int nBytesRead = 0; byte[] abData = new byte[AUDIO_BUFFER_SIZE]; while (nBytesRead != -1 && play) { try { nBytesRead = inputStream.read(abData, 0, abData.length); } catch (IOException e) { addDebugMessage("Unable to read data stream: " + e.getMessage()); } if (nBytesRead >= 0) { line.write(abData, 0, nBytesRead); } } line.stop(); line.close(); play = false; clearStream(); } catch (LineUnavailableException e) { addDebugMessage("Unable to play music: " + e.getMessage()); } addDebugMessage("Stopped playing."); } private void clearStream() { if (inputStream != null) { try { inputStream.close(); } catch (IOException e) { // We don't do anything in this case. } } } @Override public void play(IAudioFile audioFile) { if (isPlaying()) { return; } addDebugMessage("Started playing: " + audioFile.getDisplayName()); int audioFileDurationInSeconds = (int) (audioFile.getDuration() / 1000); // Load random audio input stream extract of this track int extractLength = Integer.valueOf(bundle.getString("imc.audio.determine_bpm.trackLength")); if (!audioFile.isLongEnoughFor(extractLength)) { extractLength = audioFileDurationInSeconds; } int extractStart = (audioFileDurationInSeconds - extractLength) / 2; try { inputStream = soundHelper.getLeveledStream(soundHelper.getStreamExtract(audioFile.getAudioInputStream(), extractStart, extractLength), audioFile.getVolumeRatio()); } catch (IOException e) { messageProducer.send(new ErrorMessage(e.getMessage())); addDebugMessage(e); } if (inputStream != null) { new Thread(this).start(); } } private void addDebugMessage(String message) { messageProducer.send(new DebugMessage(this, message)); } private void addDebugMessage(Throwable throwable) { messageProducer.send(new DebugMessage(this, throwable)); } }